package com.xq.hibernate;

import com.xq.hibernate.entity.Event;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Before;
import org.junit.Test;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * 功能说明: 测试一二级缓存
 * <p>创建时间: 2018-11-02 08:28</p>
 *
 * @author 郭凯强
 * @version 1.0-SNAPSHOT
 */
public class NativeApiTest02Cache extends BaseNativeApiTest {
    /**
     * 准备测试数据
     */
    @Before
    public void prepareData() throws Exception {
        Session session = this.getSessionFactory().openSession();
        Transaction transaction = session.beginTransaction();

        //保存三条数据
        session.save(new Event("第1个事件", new Date()));
        session.save(new Event("第2个事件", new Date()));
        session.save(new Event("第3个事件", new Date()));
//        session.save(new Event("第4个事件", new Date()));

        transaction.commit();
        session.close();
    }

    /**
     * 测试一级缓存
     */
    @Test
    public void testSessionCache() {
        Session session = this.getNewSession();
        Transaction transaction = session.beginTransaction();

        Event event = session.get(Event.class, 1L);
        System.out.println(event);
        // 同一个一级Session, 第二次查询时,使用缓存
        event = session.get(Event.class, 1L);

        transaction.commit();
        session.close();
    }

    /**
     * 一级缓存无法取消,但可以使用evict和clear方法管理
     *
     * @throws Exception
     */
    @Test
    public void testSessionCacheManagerMethod() throws Exception {
        Session session = this.getNewSession();
        Transaction transaction = session.beginTransaction();

        //第一次获取时,输出查询语句
        Event event = session.get(Event.class, 1L);
        //在同一个Session中第二次查询时,不输出查询语句
        event = session.get(Event.class, 1L);
        // 使用evict() 删除指定PO对象
        session.evict(event);
        System.out.println("===========after evice()==================");
        event = session.get(Event.class, 1L);
        // 将所有的Event PO缓存
        Query<Event> query = session.createQuery("from Event", Event.class);
        query.list().forEach(System.out::println);
        System.out.println("=============after query.list()===========");
        event = session.get(Event.class, 1L);
        event = session.get(Event.class, 2L);
        event = session.get(Event.class, 3L);
        //  使用clear() 清除所有缓存
        session.clear();
        System.out.println("=============after clear() ===========");
        event = session.get(Event.class, 1L);

        transaction.commit();
        session.close();
    }

    /**
     * 测试一级缓存的list和iterator方法
     *
     * @throws Exception
     */
    @Test
    public void testSessionCacheListAndIterator() throws Exception {
        Session session = this.getNewSession();
        Transaction transaction = session.beginTransaction();

        Query<Event> query = session.createQuery("from Event", Event.class);
        List<Event> list = query.list();
        System.out.println("==========after query.list()===========");
        //第二次执行query.list()时, 缓存不生效
        query.list().forEach(System.out::println);
        //使用query.iterator时,缓存生效, 且仅查询缓存的主键ID
        Iterator<Event> iterator = query.iterate();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        transaction.commit();
        session.close();
    }

    /**
     * Hibernate的二级缓存(应用级缓存)测试.
     * <p>
     * 有些数据, 在一个Session缓存后, 希望在其他的Session中能够直接使用(不希望再次缓存) => 二级缓存(共享缓存)
     * </p>
     *
     * @throws Exception
     */
    @Test
    public void testApplicationCache() throws Exception {
        Session session = this.getNewSession();
        Transaction transaction = session.beginTransaction();
        Event event = session.get(Event.class, 1L);
        System.out.println(event);
        transaction.commit();
        session.close();

        session = this.getNewSession();
        transaction = session.beginTransaction();
        event = session.get(Event.class, 1L);
        System.out.println(event);
        transaction.commit();
        session.close();
    }
}
